#include "TimerPPImp.h"


#if defined (OS_IS_WIN)
#include <mmsystem.h>
#elif defined(OS_IS_LNIX)
	#define CLOCKID CLOCK_MONOTONIC
#endif ///




namespace oct_tk
{

	/// --------------------------------------------------------------------------------
	/// @brief: TimerImp::~TimerImp
	/// --------------------------------------------------------------------------------
	TimerPPImp::~TimerPPImp()
	{
		end_();
	}

	/// --------------------------------------------------------------------------------
	/// @brief: TimerPPImp::TimerPPImp
	/// --------------------------------------------------------------------------------
	TimerPPImp::TimerPPImp()
	{
#if defined(OS_IS_WIN)
		;
#elif  defined (OS_IS_LNIX)
		const int signo = SIGRTMIN;

		// We create a static handler catches the signal SIG
		sa.sa_flags = SA_SIGINFO;
		sa.sa_sigaction = handler;
		sigemptyset(&sa.sa_mask);
		if (sigaction(signo, &sa, NULL) == -1)
			throw("Could not create signal handler");

		// Create the timer
		sev.sigev_notify = SIGEV_SIGNAL;
		sev.sigev_signo = signo;
		// Cruical is that the signal carries the pointer to this class instance here
		// because the handler just handles anything that comes in!
		sev.sigev_value.sival_ptr = this;
		// create the timer
		if (timer_create(CLOCKID, &sev, &timerid) == -1)
			throw("Could not create timer");
#endif ///
	}

	/// --------------------------------------------------------------------------------
	/// @brief: TimerImp::init_
	/// --------------------------------------------------------------------------------
	int TimerPPImp::init_(const TimerType&& tt, ITimerCallBack* pcb)
	{

		/// 1. 参数错误
		if ((ITimerPP::TIMER_TYPE_PERIODIC != tt) && (ITimerPP::TIMER_TYPE_ONE_SHORT != tt))
		{
			return 1;
		}

		timer_type_		= tt;
		pcallback_func_ = pcb;
		
		return 0;
	}

	/// --------------------------------------------------------------------------------
	/// @brief: TimerImp::begin_
	/// --------------------------------------------------------------------------------
	int TimerPPImp::begin_(const uint&& interval_ms)
	{
		/// 周期不能为0
		if (0 == interval_ms)
		{
			return 1;
		}

#if defined (OS_IS_WIN)
		/// 1. 避免周期调用start函数
		this->end_();

		/// 2. 启动定时器
		if (NULL == (timer_id_ = timeSetEvent(interval_ms, NULL, TimeProc, (DWORD_PTR)this, static_cast<int>(timer_type_))) )
		{
			return 2;
		}
#elif defined(OS_IS_LNIX)
		switch (timer_type_)
		{
		case (oct_tk::ITimerPP::TIMER_TYPE_PERIODIC):
			//starts after specified period of milliseconds
			its.it_value.tv_sec = interval_ms / 1000;
			its.it_value.tv_nsec = (interval_ms % 1000) * 1000000;
			its.it_interval.tv_sec = interval_ms / 1000;
			its.it_interval.tv_nsec = (interval_ms % 1000) * 1000000;
			break;
		case (oct_tk::ITimerPP::TIMER_TYPE_ONE_SHORT):
			//fires once after specified period of milliseconds
			its.it_value.tv_sec = interval_ms / 1000;
			its.it_value.tv_nsec = (interval_ms % 1000) * 1000000;
			its.it_interval.tv_sec = 0;
			its.it_interval.tv_nsec = 0;
			break;
		}

		int retttt = timer_settime(timerid, 0, &its, NULL); 
		if ( -1 == retttt)
		{
			perror("\n timer_settime \n error , ret=-1");
			return 2;
		}
			
#endif ///

		return 0;
	}

	/// --------------------------------------------------------------------------------
	/// @brief: TimerImp::end_
	/// --------------------------------------------------------------------------------
	int TimerPPImp::end_()
	{
#if defined (OS_IS_WIN)
		if (0 != timer_id_)
		{
			timeKillEvent(timer_id_);
			timer_id_ = 0;
		}
		else
		{
			/// 定时器无效
			;
		}
#elif defined(OS_IS_LNIX)

		if (nullptr != timerid)
		{
			struct itimerspec itsnew;
			itsnew.it_value.tv_sec = 0;
			itsnew.it_value.tv_nsec = 0;
			itsnew.it_interval.tv_sec = 0;
			itsnew.it_interval.tv_nsec = 0;
			timer_settime(timerid, 0, &itsnew, &its);
		
			timer_delete(timerid);
			// default action for signal handling
			signal(sev.sigev_signo, SIG_IGN);

			timerid = nullptr;
		}
		

#endif ///

		return 0;

	}

# if defined(OS_IS_WIN)
	/// --------------------------------------------------------------------------------
	/// @brief: TimerImp::TimeProc
	/// --------------------------------------------------------------------------------
	void CALLBACK TimerPPImp::TimeProc(UINT uTimerID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2)
	{
		TimerPPImp* ptimer = (TimerPPImp*)(dwUser);
		if (ptimer)
		{
			///  执行回调函数
			if (ptimer->pcallback_func_)
			{
				ptimer->pcallback_func_->timer_call_back_();
			}
			else
			{
				/// 定时器回调函数无效
				;///
			}
		}
		else
		{
			/// 定时器无效
			;
		}
	}

#endif /// endif 

}